﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Xml;
using System.Xml.Linq;
using System.Globalization;
using EpiMapit.Properties;
using System.Diagnostics;

namespace EpiMapit
{
    public partial class MainForm : Form
    {

        [STAThread]
        public static void Main()
        {
			Application.CurrentCulture = CultureInfo.InvariantCulture;
            Application.Run(new MainForm());
        }

        public MainForm()
        {
            InitializeComponent();
            scaleRelationships.Value = (decimal)ControlConstants.CircleScalingLogBase;
            scaleRelationships.Minimum = (decimal)ControlConstants.MinCircleScalingLogBase;
            scaleRelationships.Maximum = (decimal)ControlConstants.MaxCircleScalingLogBase;

            DisplayColors();
            UpdateLodExplanation();
        }

        private XElement MultiGeometry(params XElement[] geometries)
        {
            return new XElement("MultiGeometry", geometries);
        }

        private void browseInputBt_Click(object sender, EventArgs e)
        {
            if (csvFileCb.Checked)
            {
                BrowseForFile();
            }
            else if (directoryCb.Checked)
            {
                BrowseForDirectory();
            }
        }

        private void BrowseForDirectory()
        {
            // Show the FolderBrowserDialog
            FolderBrowserDialog folderBrowserDialog1 = new FolderBrowserDialog();

            // Set the help text description for the FolderBrowserDialog.
            folderBrowserDialog1.Description = "Select the directory with all the CSV files.";

            // Do not allow the user to create new files via the FolderBrowserDialog.
            folderBrowserDialog1.ShowNewFolderButton = false;

            // Default to the My Documents folder.
            //folderBrowserDialog1.RootFolder = Environment.SpecialFolder.Personal;

            DialogResult result = folderBrowserDialog1.ShowDialog();
            
            if (result == DialogResult.OK)
            {
                string folderName = folderBrowserDialog1.SelectedPath;
                inputTb.Text = folderName;
            }
        }

        private void BrowseForFile()
        {
            // Displays an OpenFileDialog so the user can select a csv file.
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.Filter = "CSV files (.csv)|*.csv"; // Filter files by extension
            ofd.Title = "Choose a CSV file.";

            // Show the Dialog.
            DialogResult result = ofd.ShowDialog();

            string filename = string.Empty;

            // Process open file dialog box results
            if (result == DialogResult.OK)
            {
                filename = ofd.FileName;
                inputTb.Text = filename;
            }
        }

        private void browseOutputBt_Click(object sender, EventArgs e)
        {
            // Configure choose file dialog box
            SaveFileDialog dlg = new SaveFileDialog();
            dlg.FileName = "Epimapit"; // Default file name
            dlg.DefaultExt = ".kml"; // Default file extension
            dlg.Filter = "Kml documents (.kml)|*.kml"; // Filter files by extension

            // Show dialog box
            DialogResult result = dlg.ShowDialog();

            if (result == DialogResult.OK)
            {
                string filename = dlg.FileName;
                outputFileTb.Text = filename;
            }
        }

        private void createBt_Click(object sender, EventArgs e)
        {
            ReadColors();

            if (string.IsNullOrEmpty(inputTb.Text))
            {
                MessageBox.Show("Please choose a file or directory.");
                return;
            }

            if (string.IsNullOrEmpty(outputFileTb.Text))
            {
                MessageBox.Show("Please choose an output file.");
                return;
            }

            ControlConstants.CircleScalingLogBase = (float)scaleRelationships.Value;

            RememberTextBoxValues();

            var transform = GetCaseSetGroupTransform();
            var usePins = GetUsePins();
            var caseSetGroup = GenerateCaseSetGroup();

            int totalNumber = caseSetGroup.Sum(x => x.Levels.Values.Sum());

            var ring = new RingGenerator(totalNumber, ControlConstants.RingColors);

            var generator = new KmlGenerator(
                ring, 
                transform, 
                (int)uiLodMin.Value,
                (int)uiLodMax.Value,
                (int)uiLodLevels.Value,
                usePins);
            var doc = generator.Generate(caseSetGroup);

            using (var writer = new XmlTextWriter(outputFileTb.Text, Encoding.UTF8))
            {
                writer.Formatting = Formatting.Indented;
                doc.WriteTo(writer);
                writer.Flush();
            }

            MessageBox.Show("Done!");
        }

        private bool GetUsePins()
        {
            return !cumulativeCasesOption.Checked;
        }

        private void RememberTextBoxValues()
        {
            Settings.Default.InputCsvFile = inputTb.Text;
            Settings.Default.OutputFile = outputFileTb.Text;
            try
            {
                Settings.Default.Save();
            }
            catch
            { }
        }

        private CaseSetGroupTransform GetCaseSetGroupTransform()
        {
            if (cumulativeCasesOption.Checked)
            {
                // This just keeps the data from the last date of each region
                return x =>
                {
                    CaseSetGroup result = new CaseSetGroup();
                    x
                        .GroupBy(y => y.RegionCode)
                        .ForEach(y => result.AddRange(
                            y.Where(z =>
                                y.All(w =>
                                    z.Date >= w.Date))));
                    return result;
                };
            }
            else
            {
                return x => x;
            }
        }

        private CaseSetGroup GenerateCaseSetGroup()
        {
            var builder = new CaseSetGroupBuilder(new GeoCodingResources(), HardCodedSpec());
            if (csvFileCb.Checked)
            {
                // TODO SERch tiene que corregir esto
                return builder.GenerateCaseSetGroupFromCSV(inputTb.Text, Auxiliars.ParseDate(inputTb.Text));
            }
            else
            {
                return builder.GenerateCaseSetGroupFromDir(inputTb.Text);
            }
        }

        private Specification HardCodedSpec()
        {
            Specification spec = new Specification();
            spec.Country = 0;
            spec.Region = 1;
            spec.TwoLetterISO = 2;
            spec.GEOCode = 3;

            spec.Cases.Add("OfficialLabConfirmed", 4);
            spec.Cases.Add("OfficialUnderInvestigationCases", 5);
            spec.Cases.Add("ConfirmedDeaths", 6);
            spec.Cases.Add("OfficialUnderInvestigationDeaths", 7);

            return spec;
        }

        private string CreateChartString(string title, string chartUrl)
        {
            string ret = string.Format(@"<b>{0}:</b><img src=""{1}""></img>", title, chartUrl);
            return ret;
        }


        private void DisplayColors()
        { 
            pictureBox4.BackColor = ControlConstants.InnerRingColor;
            pictureBox3.BackColor = ControlConstants.FirstRingColor;
            pictureBox2.BackColor = ControlConstants.SecondRingColor;
            pictureBox1.BackColor = ControlConstants.ThirdRingColor;

        }

        private void ReadColors()
        {
            ControlConstants.InnerRingColor = pictureBox4.BackColor;
            ControlConstants.FirstRingColor=pictureBox3.BackColor;
            ControlConstants.SecondRingColor=pictureBox2.BackColor;
            ControlConstants.ThirdRingColor=pictureBox1.BackColor;

            ControlConstants.RingColors = new Color[] { ControlConstants.InnerRingColor, ControlConstants.FirstRingColor, ControlConstants.SecondRingColor, ControlConstants.ThirdRingColor };
        }

        private void SetColor(Control o)
        {
            colorDialog1.Color = o.BackColor;
            colorDialog1.ShowDialog(this);
            o.BackColor = colorDialog1.Color;
        }

        private void pictureBox4_Click(object sender, EventArgs e)
        {
            SetColor((Control)sender);
        }

        private void pictureBox3_Click(object sender, EventArgs e)
        {
            SetColor((Control)sender);
        }

        private void pictureBox2_Click(object sender, EventArgs e)
        {
            SetColor((Control)sender);
        }

        private void pictureBox1_Click(object sender, EventArgs e)
        {
            SetColor((Control)sender);
        }

        private void uiLodMin_ValueChanged(object sender, EventArgs e)
        {
            uiLodMax.Minimum = uiLodMin.Value;
            UpdateLodExplanation();
        }

        private void uiLodLevels_ValueChanged(object sender, EventArgs e)
        {
            uiLodMax.Enabled = labelLodMax.Enabled = uiLodLevels.Value >= 2;
            UpdateLodExplanation();
        }

        private void uiLodMax_ValueChanged(object sender, EventArgs e)
        {
            UpdateLodExplanation();
        }

        private void UpdateLodExplanation()
        {
            if (uiLodLevels.Value == 1)
            {
                labelLodExplanation.Text = "Only one level of " + (int)uiLodMin.Value + "Km will be drawn";
            }
            else if (uiLodLevels.Value == 2)
            {
                labelLodExplanation.Text = "Levels of " + (int)uiLodMin.Value + "Km and " + (int)uiLodMax.Value + "Km will be drawn";
            } 
            else
            {
                var lodMin = (double)uiLodMin.Value;
                var lodMax = (double)uiLodMax.Value;
                var lodSteps = (int)uiLodLevels.Value;
                var lodBase = Math.Pow(10, Math.Log(lodMax / lodMin, 10) / (lodSteps - 1));

                StringBuilder sb = new StringBuilder();
                sb.Append("Levels of ");
                for (int i = 0; i < lodSteps; i++)
                {
                    float cluster = (float)(lodMin * Math.Pow(lodBase, i));
                    sb.Append(string.Format("{0:0.##}Km", cluster));

                    if (i == lodSteps - 2)
                    {
                        sb.Append(" and ");
                    }
                    else if (i < lodSteps - 2)
                    {
                        sb.Append(", ");
                    }
                }
                sb.Append(" will be drawn");

                labelLodExplanation.Text = sb.ToString();
            }
        }
    }
}
